{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "total = pd.read_csv('total.csv', encoding='latin-1')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Id</th>\n",
       "      <th>OwnerUserId</th>\n",
       "      <th>CreationDate</th>\n",
       "      <th>ClosedDate</th>\n",
       "      <th>Score</th>\n",
       "      <th>Title</th>\n",
       "      <th>Body</th>\n",
       "      <th>month</th>\n",
       "      <th>year</th>\n",
       "      <th>Tag</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>80</td>\n",
       "      <td>26.0</td>\n",
       "      <td>2008-08-01 13:57:07</td>\n",
       "      <td>NaN</td>\n",
       "      <td>26</td>\n",
       "      <td>SQLStatement.execute() - multiple queries in o...</td>\n",
       "      <td>&lt;p&gt;I've written a database generation script i...</td>\n",
       "      <td>8</td>\n",
       "      <td>2008</td>\n",
       "      <td>flex</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>80</td>\n",
       "      <td>26.0</td>\n",
       "      <td>2008-08-01 13:57:07</td>\n",
       "      <td>NaN</td>\n",
       "      <td>26</td>\n",
       "      <td>SQLStatement.execute() - multiple queries in o...</td>\n",
       "      <td>&lt;p&gt;I've written a database generation script i...</td>\n",
       "      <td>8</td>\n",
       "      <td>2008</td>\n",
       "      <td>actionscript-3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>80</td>\n",
       "      <td>26.0</td>\n",
       "      <td>2008-08-01 13:57:07</td>\n",
       "      <td>NaN</td>\n",
       "      <td>26</td>\n",
       "      <td>SQLStatement.execute() - multiple queries in o...</td>\n",
       "      <td>&lt;p&gt;I've written a database generation script i...</td>\n",
       "      <td>8</td>\n",
       "      <td>2008</td>\n",
       "      <td>air</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>90</td>\n",
       "      <td>58.0</td>\n",
       "      <td>2008-08-01 14:41:24</td>\n",
       "      <td>2012-12-26 03:45:49</td>\n",
       "      <td>144</td>\n",
       "      <td>Good branching and merging tutorials for Torto...</td>\n",
       "      <td>&lt;p&gt;Are there any really good tutorials explain...</td>\n",
       "      <td>8</td>\n",
       "      <td>2008</td>\n",
       "      <td>svn</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>90</td>\n",
       "      <td>58.0</td>\n",
       "      <td>2008-08-01 14:41:24</td>\n",
       "      <td>2012-12-26 03:45:49</td>\n",
       "      <td>144</td>\n",
       "      <td>Good branching and merging tutorials for Torto...</td>\n",
       "      <td>&lt;p&gt;Are there any really good tutorials explain...</td>\n",
       "      <td>8</td>\n",
       "      <td>2008</td>\n",
       "      <td>tortoisesvn</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   Id  OwnerUserId         CreationDate           ClosedDate  Score  \\\n",
       "0  80         26.0  2008-08-01 13:57:07                  NaN     26   \n",
       "1  80         26.0  2008-08-01 13:57:07                  NaN     26   \n",
       "2  80         26.0  2008-08-01 13:57:07                  NaN     26   \n",
       "3  90         58.0  2008-08-01 14:41:24  2012-12-26 03:45:49    144   \n",
       "4  90         58.0  2008-08-01 14:41:24  2012-12-26 03:45:49    144   \n",
       "\n",
       "                                               Title  \\\n",
       "0  SQLStatement.execute() - multiple queries in o...   \n",
       "1  SQLStatement.execute() - multiple queries in o...   \n",
       "2  SQLStatement.execute() - multiple queries in o...   \n",
       "3  Good branching and merging tutorials for Torto...   \n",
       "4  Good branching and merging tutorials for Torto...   \n",
       "\n",
       "                                                Body  month  year  \\\n",
       "0  <p>I've written a database generation script i...      8  2008   \n",
       "1  <p>I've written a database generation script i...      8  2008   \n",
       "2  <p>I've written a database generation script i...      8  2008   \n",
       "3  <p>Are there any really good tutorials explain...      8  2008   \n",
       "4  <p>Are there any really good tutorials explain...      8  2008   \n",
       "\n",
       "              Tag  \n",
       "0            flex  \n",
       "1  actionscript-3  \n",
       "2             air  \n",
       "3             svn  \n",
       "4     tortoisesvn  "
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1048465, 10)"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<p>I\\'ve written a database generation script in <a href=\"http://en.wikipedia.org/wiki/SQL\">SQL</a> and want to execute it in my <a href=\"http://en.wikipedia.org/wiki/Adobe_Integrated_Runtime\">Adobe AIR</a> application:</p>\\r\\r<pre><code>Create Table tRole (\\r      roleID integer Primary Key\\r      ,roleName varchar(40)\\r);\\rCreate Table tFile (\\r    fileID integer Primary Key\\r    ,fileName varchar(50)\\r    ,fileDescription varchar(500)\\r    ,thumbnailID integer\\r    ,fileFormatID integer\\r    ,categoryID integer\\r    ,isFavorite boolean\\r    ,dateAdded date\\r    ,globalAccessCount integer\\r    ,lastAccessTime date\\r    ,downloadComplete boolean\\r    ,isNew boolean\\r    ,isSpotlight boolean\\r    ,duration varchar(30)\\r);\\rCreate Table tCategory (\\r    categoryID integer Primary Key\\r    ,categoryName varchar(50)\\r    ,parent_categoryID integer\\r);\\r...\\r</code></pre>\\r\\r<p>I execute this in Adobe AIR using the following methods:</p>\\r\\r<pre><code>public static function RunSqlFromFile(fileName:String):void {\\r    var file:File = File.applicationDirectory.resolvePath(fileName);\\r    var stream:FileStream = new FileStream();\\r    stream.open(file, FileMode.READ)\\r    var strSql:String = stream.readUTFBytes(stream.bytesAvailable);\\r    NonQuery(strSql);\\r}\\r\\rpublic static function NonQuery(strSQL:String):void\\r{\\r    var sqlConnection:SQLConnection = new SQLConnection();\\r    sqlConnection.open(File.applicationStorageDirectory.resolvePath(DBPATH);\\r    var sqlStatement:SQLStatement = new SQLStatement();\\r    sqlStatement.text = strSQL;\\r    sqlStatement.sqlConnection = sqlConnection;\\r    try\\r    {\\r        sqlStatement.execute();\\r    }\\r    catch (error:SQLError)\\r    {\\r        Alert.show(error.toString());\\r    }\\r}\\r</code></pre>\\r\\r<p>No errors are generated, however only <code>tRole</code> exists. It seems that it only looks at the first query (up to the semicolon- if I remove it, the query fails). Is there a way to call multiple queries in one statement?</p>\\r'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total['Body'][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import Counter\n",
    "import numpy as np \n",
    "import string\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "def clean_text(text):\n",
    "    global EMPTY\n",
    "    EMPTY = ''\n",
    "    \n",
    "    if not isinstance(text, str): \n",
    "        return text\n",
    "    text = re.sub('<pre><code>.*?</code></pre>', EMPTY, text)\n",
    "\n",
    "    def replace_link(match):\n",
    "        return EMPTY if re.match('[a-z]+://', match.group(1)) else match.group(1)\n",
    "    \n",
    "    text = re.sub('<a[^>]+>(.*)</a>', replace_link, text)\n",
    "    return re.sub('<[^>]+>', EMPTY, text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "total['Text'] = total['Body'].apply(clean_text).str.lower()\n",
    "total.Text = total.Text.apply(lambda x: x.replace('\"','').replace(\"\\n\",\"\").replace(\"\\t\",\"\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "21981"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total['Tag'].nunique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_tags(tagCount):\n",
    "    \n",
    "    x,y = zip(*tagCount)\n",
    "\n",
    "    colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired  \n",
    "    colors = [colormap(i) for i in np.linspace(0, 0.8,50)]   \n",
    "\n",
    "    area = [i/4000 for i in list(y)]   # 0 to 15 point radiuses\n",
    "    plt.figure(figsize=(10,6))\n",
    "    plt.ylabel(\"Number of question associations\")\n",
    "    for i in range(len(y)):\n",
    "        plt.plot(i,y[i], marker='o', linestyle='',ms=area[i],label=x[i])\n",
    "\n",
    "    plt.legend(numpoints=1)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('c#', 34977), ('java', 29263), ('php', 27835), ('javascript', 26194), ('jquery', 22807), ('android', 22193), ('c++', 14690), ('iphone', 14481), ('python', 13469), ('asp.net', 13433)]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nbRq0qVT/ZlbqcVJS6Jrx8fEUFBRUWD/WKaETERGRiBnUZhCJ8YmlnkuIT+DMNmdWqv+NGzeyaNEi\nAF544QXOOOOMcuvPmjWLgwcPsnPnTubNm0evXr0qdf2aQgmdiIiIRExCfAITB0+kUVIj6tWqR7zF\nU69WPRolNWLi4IkkxCdUqv+OHTsyZcoU0tLSyM7OZvz48eXW7927N0OHDqVPnz7cc889tGzZslLX\nrym0bYmIiIhEVIfkDsy5eA5zN81lU84m2jRow5ltzqx0MgcQFxfHU089dVhZyTlzGRkZzJs3r/j4\nlFNO4emnn670dWsaJXQiIiIScQnxCQxOHRztMI5ZSuhEREQkJqWmpvLxxx+HXf++++6LXDBRpjl0\nIiIiIjFOCZ2IiIhIjFNCJyIiIhLjlNCJiIiIxDgldCIiIlIt8rdsYd+iReRv2VJlffbt27fK+qqM\nrVu3MnLkyHLr7N69u/hds1VNCZ2IiIhEVOF337HxmnF8cd5QNt9wI1+cN5SN14yj8LvvKt33woUL\nqyDCyikoKKBly5bMmDGj3HpK6ERERCRmbbnpZvYvXozn5lKUk4Pn5rJ/8WK23HxzpfuuX78+3333\nHWeddRY9evSga9euzJo1C4Dbb7/9sATqvvvuY8KECWXW37dvH0OHDqVbt2506dKF6dOnA7B06VL6\n9u1Lt27d6N27Nzk5OUyePJmLL76YCy64gMGDB5OVlUWXLl0AmDx5MhdddBHnnnsup556Kn/4wx8A\nuOOOO/jiiy9IT0/ntttuq/S9l6R96ERERCRi8jZvYf/SpXh+/mHlnp/P/iVLyd+yhYRWrSp1jdq1\nazNz5kwaNmzIjh076NOnDxdeeCGjRo3ipptu4je/+Q0AL774Im+++WaZ9d98801atmzJa6+9BsCe\nPXvIy8vjl7/8JdOnT6dXr17s3buXOnXqALBo0SJWrVpFcnLyYW+nAFiyZAkff/wxdevWpVevXgwd\nOpSHHnqIjz/+mBUrVlTqfkujEToRERGJmPxNG7HExFLPWWIieRs3Vvoa7s5dd91FWloaP//5z9my\nZQvffvst3bt3Z9u2bWzdupWVK1fSuHFjUlJSyqzftWtX3n33XW6//Xbef/99TjjhBD777DNatGhB\nr169AGjYsCG1aoXGw84++2ySk5NLjenss8+mSZMm1KlThxEjRrBgwYJK32d5NEInIiIiEZPQJgXP\n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\nXLGK9gg2s8Xuflo1xRNxGRkZnpmZGe0wRERERCpkZsvcPaOieuGM0D1mZvcCbwO5hwoPbUkiIiIi\nItEVTkLXldCj00F8/8jVg2MRERERibJwErrhQDt3z4t0MCIiIiJy5MJ5U8RKoFGkAxERERGRoxPO\nCN1PgE/NbCmHz6G7MGJRiYiIiEjYwkno7o14FCIiIiJy1CpM6Nz9veoIRERERESOToUJnZnl8P07\nUhOBBGCfuzeMZGAiIiIiEp5wRugalDw2s2FA74hFJCIiIiJHJJxVrodx91fQHnQiIiIiNUY4j1xH\nlDiMAzL4/hGsiIiIiERZOKtcLyjxvQDIAi6KSDQiIiIicsTCmUM3tjoCEREREZGjU2ZCZ2a/L6ed\nu/sDEYhHRERERI5QeSN0+0opqwdcDTQBlNCJiIiI1ABlJnTuPuHQdzNrANwIjAWmARPKaiciIiIi\n1avcOXRmlgz8DrgMmAL0cPdd1RGYiIiIiISnvDl0DwMjgKeBru7+XbVFJSIiIiJhK29j4VuAlsB/\nAVvNbG/wyTGzvdUTnoiIiIhUpLw5dEf8FgkRERERqX5K2kRERERinBI6ERERkRinhE5EREQkximh\nExEREYlxSuhEREREYpwSOhEREZEYp4ROREREJMYpoRMRERGJcUroRERERGKcEjoRERGRGKeETkRE\nRCTGKaETERERiXFK6ERERERinBI6ERERkRinhE5EREQkximhExEREYlxSuhEREREYpwSOhEREZEY\np4ROREREJMYpoRMRERGJcUroRERERGKcEjoRERGRGKeETkRERCTGKaETERERiXFK6ERERERinBI6\nERERkRinhE5EREQkximhExEREYlxSuhEREREYpwSOhEREZEYp4ROREREJMYpoRMRERGJcUroRERE\nRGKcEjoRERGRGKeETkRERCTGKaETERERiXFK6ERERERinBI6ERERkRinhE5EREQkxkUsoTOzSWa2\nzcw+LlF2n5ltMbMVwee8EufuNLP1ZvaZmZ1TovzcoGy9md1RorytmS02s3VmNt3MEiN1LyIiIiI1\nWSRH6CYD55ZS/qi7pwef1wHMrBMwCugctHnSzOLNLB74BzAE6ARcEtQF+EvQV3tgF3B1BO9FRERE\npMaKWELn7vOB7DCrXwRMc/dcd/8SWA/0Dj7r3X2Du+cB04CLzMyAQcCMoP0UYFiV3oCIiIhIjIjG\n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\nlTTVrIMCAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10bf67a90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import collections\n",
    "import matplotlib.pyplot as plt\n",
    "tagCount =  collections.Counter(list(total['Tag'])).most_common(10)\n",
    "print(tagCount)\n",
    "plot_tags(tagCount)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [],
   "source": [
    "total = total[(total.Tag == 'c#') | (total.Tag == 'java') | (total.Tag == 'php') | (total.Tag =='javascript') | (total.Tag =='jquery') | (total.Tag == 'android') | (total.Tag == 'c++') | (total.Tag == 'iphone') | (total.Tag == 'python') | (total.Tag == 'asp.net')]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "c#            34977\n",
       "java          29263\n",
       "php           27835\n",
       "javascript    26194\n",
       "jquery        22807\n",
       "android       22193\n",
       "c++           14690\n",
       "iphone        14481\n",
       "python        13469\n",
       "asp.net       13433\n",
       "Name: Tag, dtype: int64"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total['Tag'].value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "\n",
    "import logging\n",
    "import numpy as np\n",
    "from optparse import OptionParser\n",
    "import sys\n",
    "from time import time\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "from sklearn.feature_extraction.text import HashingVectorizer\n",
    "from sklearn.feature_selection import SelectFromModel\n",
    "from sklearn.feature_selection import SelectKBest, chi2\n",
    "from sklearn.linear_model import RidgeClassifier\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.svm import LinearSVC\n",
    "from sklearn.linear_model import SGDClassifier\n",
    "from sklearn.linear_model import Perceptron\n",
    "from sklearn.linear_model import PassiveAggressiveClassifier\n",
    "from sklearn.naive_bayes import BernoulliNB, MultinomialNB\n",
    "from sklearn.neighbors import NearestCentroid\n",
    "from sklearn.utils.extmath import density\n",
    "from sklearn import metrics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "logging.basicConfig(level=logging.INFO,\n",
    "                    format='%(asctime)s %(levelname)s %(message)s')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Option at 0x1a4bb48278: --filtered>"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# parse commandline arguments\n",
    "op = OptionParser()\n",
    "op.add_option(\"--report\",\n",
    "              action=\"store_true\", dest=\"print_report\",\n",
    "              help=\"Print a detailed classification report.\")\n",
    "op.add_option(\"--chi2_select\",\n",
    "              action=\"store\", type=\"int\", dest=\"select_chi2\",\n",
    "              help=\"Select some number of features using a chi-squared test\")\n",
    "op.add_option(\"--confusion_matrix\",\n",
    "              action=\"store_true\", dest=\"print_cm\",\n",
    "              help=\"Print the confusion matrix.\")\n",
    "op.add_option(\"--top10\",\n",
    "              action=\"store_true\", dest=\"print_top10\",\n",
    "              help=\"Print ten most discriminative terms per class\"\n",
    "                   \" for every classifier.\")\n",
    "op.add_option(\"--all_categories\",\n",
    "              action=\"store_true\", dest=\"all_categories\",\n",
    "              help=\"Whether to use all categories or not.\")\n",
    "op.add_option(\"--use_hashing\",\n",
    "              action=\"store_true\",\n",
    "              help=\"Use a hashing vectorizer.\")\n",
    "op.add_option(\"--n_features\",\n",
    "              action=\"store\", type=int, default=2 ** 16,\n",
    "              help=\"n_features when using the hashing vectorizer.\")\n",
    "op.add_option(\"--filtered\",\n",
    "              action=\"store_true\",\n",
    "              help=\"Remove newsgroup information that is easily overfit: \"\n",
    "                   \"headers, signatures, and quoting.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Automatically created module for IPython interactive environment\n",
      "Usage: ipykernel_launcher.py [options]\n",
      "\n",
      "Options:\n",
      "  -h, --help            show this help message and exit\n",
      "  --report              Print a detailed classification report.\n",
      "  --chi2_select=SELECT_CHI2\n",
      "                        Select some number of features using a chi-squared\n",
      "                        test\n",
      "  --confusion_matrix    Print the confusion matrix.\n",
      "  --top10               Print ten most discriminative terms per class for\n",
      "                        every classifier.\n",
      "  --all_categories      Whether to use all categories or not.\n",
      "  --use_hashing         Use a hashing vectorizer.\n",
      "  --n_features=N_FEATURES\n",
      "                        n_features when using the hashing vectorizer.\n",
      "  --filtered            Remove newsgroup information that is easily overfit:\n",
      "                        headers, signatures, and quoting.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def is_interactive():\n",
    "    return not hasattr(sys.modules['__main__'], '__file__')\n",
    "\n",
    "# work-around for Jupyter notebook and IPython console\n",
    "argv = [] if is_interactive() else sys.argv[1:]\n",
    "(opts, args) = op.parse_args(argv)\n",
    "if len(args) > 0:\n",
    "    op.error(\"this script takes no arguments.\")\n",
    "    sys.exit(1)\n",
    "\n",
    "print(__doc__)\n",
    "op.print_help()\n",
    "print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1a4b6d23c8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(10,6))\n",
    "total.groupby('Tag').Text.count().plot.bar(ylim=0)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "col = ['Id', 'OwnerUserId', 'CreationDate', 'ClosedDate', 'Score', 'Title', 'Body', 'month', 'year']\n",
    "total.drop(col, axis=1, inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Tag</th>\n",
       "      <th>Text</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>c#</td>\n",
       "      <td>i have two tabitems. user will enter some data...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>python</td>\n",
       "      <td>python's unittest testrunner looks for setupmo...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>javascript</td>\n",
       "      <td>i have an xslt file hosted www.mydomain.com/my...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>android</td>\n",
       "      <td>i have found several tutorials for making a ti...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>android</td>\n",
       "      <td>i'm writing media files share application.\\r\\r...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          Tag                                               Text\n",
       "0          c#  i have two tabitems. user will enter some data...\n",
       "1      python  python's unittest testrunner looks for setupmo...\n",
       "2  javascript  i have an xslt file hosted www.mydomain.com/my...\n",
       "3     android  i have found several tutorials for making a ti...\n",
       "4     android  i'm writing media files share application.\\r\\r..."
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "total = total.sample(frac=1).reset_index(drop=True)\n",
    "total.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "categories = total['Tag'].unique()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "X_train, X_test, y_train, y_test = train_test_split(total['Text'], total['Tag'], random_state=42, test_size=0.2, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "175473 documents - 92.099MB (training set)\n",
      "43869 documents - 23.062MB (test set)\n",
      "10 categories\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def size_mb(docs):\n",
    "    return sum(len(s.encode('utf-8')) for s in docs) / 1e6\n",
    "\n",
    "data_train_size_mb = size_mb(X_train)\n",
    "data_test_size_mb = size_mb(X_test)\n",
    "\n",
    "print(\"%d documents - %0.3fMB (training set)\" % (\n",
    "    len(X_train), data_train_size_mb))\n",
    "print(\"%d documents - %0.3fMB (test set)\" % (\n",
    "    len(X_test), data_test_size_mb))\n",
    "print(\"%d categories\" % len(categories))\n",
    "print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting features from the training data using a sparse vectorizer\n",
      "done in 12.389807s at 7.433MB/s\n",
      "n_samples: 175473, n_features: 173624\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(\"Extracting features from the training data using a sparse vectorizer\")\n",
    "t0 = time()\n",
    "if opts.use_hashing:\n",
    "    vectorizer = HashingVectorizer(stop_words='english', alternate_sign=False,\n",
    "                                   n_features=opts.n_features)\n",
    "    X_train_1 = vectorizer.transform(X_train)\n",
    "else:\n",
    "    vectorizer = TfidfVectorizer(sublinear_tf=True, max_df=0.5,\n",
    "                                 stop_words='english')\n",
    "    X_train_1 = vectorizer.fit_transform(X_train)\n",
    "duration = time() - t0\n",
    "print(\"done in %fs at %0.3fMB/s\" % (duration, data_train_size_mb / duration))\n",
    "print(\"n_samples: %d, n_features: %d\" % X_train_1.shape)\n",
    "print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting features from the test data using the same vectorizer\n",
      "done in 3.099743s at 7.440MB/s\n",
      "n_samples: 43869, n_features: 173624\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(\"Extracting features from the test data using the same vectorizer\")\n",
    "t0 = time()\n",
    "X_test_1 = vectorizer.transform(X_test)\n",
    "duration = time() - t0\n",
    "print(\"done in %fs at %0.3fMB/s\" % (duration, data_test_size_mb / duration))\n",
    "print(\"n_samples: %d, n_features: %d\" % X_test_1.shape)\n",
    "print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "# mapping from integer feature name to original token string\n",
    "if opts.use_hashing:\n",
    "    feature_names = None\n",
    "else:\n",
    "    feature_names = vectorizer.get_feature_names()\n",
    "\n",
    "if opts.select_chi2:\n",
    "    print(\"Extracting %d best features by a chi-squared test\" %\n",
    "          opts.select_chi2)\n",
    "    t0 = time()\n",
    "    ch2 = SelectKBest(chi2, k=opts.select_chi2)\n",
    "    X_train_1 = ch2.fit_transform(X_train_1, y_train)\n",
    "    X_test_1 = ch2.transform(X_test_1)\n",
    "    if feature_names:\n",
    "        # keep selected feature names\n",
    "        feature_names = [feature_names[i] for i\n",
    "                         in ch2.get_support(indices=True)]\n",
    "    print(\"done in %fs\" % (time() - t0))\n",
    "    print()\n",
    "\n",
    "if feature_names:\n",
    "    feature_names = np.asarray(feature_names)\n",
    "\n",
    "\n",
    "def trim(s):\n",
    "    \"\"\"Trim string to fit on terminal (assuming 80-column display)\"\"\"\n",
    "    return s if len(s) <= 80 else s[:77] + \"...\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "target_names=categories"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================================================================\n",
      "Ridge Classifier\n",
      "________________________________________________________________________________\n",
      "Training: "
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/sli/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/ridge.py:319: UserWarning: In Ridge, only 'sag' solver can currently fit the intercept when X is sparse. Solver has been automatically changed into 'sag'.\n",
      "  warnings.warn(\"In Ridge, only 'sag' solver can currently fit the \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "RidgeClassifier(alpha=1.0, class_weight=None, copy_X=True, fit_intercept=True,\n",
      "        max_iter=None, normalize=False, random_state=None, solver='lsqr',\n",
      "        tol=0.01)\n",
      "train time: 33.990s\n",
      "test time:  0.041s\n",
      "accuracy:   0.691\n",
      "dimensionality: 173624\n",
      "density: 0.999999\n",
      "\n",
      "\n",
      "================================================================================\n",
      "Perceptron\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "Perceptron(alpha=0.0001, class_weight=None, eta0=1.0, fit_intercept=True,\n",
      "      max_iter=None, n_iter=50, n_jobs=1, penalty=None, random_state=0,\n",
      "      shuffle=True, tol=None, verbose=0, warm_start=False)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/sli/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/stochastic_gradient.py:117: DeprecationWarning: n_iter parameter is deprecated in 0.19 and will be removed in 0.21. Use max_iter and tol instead.\n",
      "  DeprecationWarning)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train time: 28.230s\n",
      "test time:  0.035s\n",
      "accuracy:   0.562\n",
      "dimensionality: 173624\n",
      "density: 0.326743\n",
      "\n",
      "\n",
      "================================================================================\n",
      "Passive-Aggressive\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "PassiveAggressiveClassifier(C=1.0, average=False, class_weight=None,\n",
      "              fit_intercept=True, loss='hinge', max_iter=None, n_iter=50,\n",
      "              n_jobs=1, random_state=None, shuffle=True, tol=None,\n",
      "              verbose=0, warm_start=False)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/sli/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/stochastic_gradient.py:117: DeprecationWarning: n_iter parameter is deprecated in 0.19 and will be removed in 0.21. Use max_iter and tol instead.\n",
      "  DeprecationWarning)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train time: 33.418s\n",
      "test time:  0.041s\n",
      "accuracy:   0.591\n",
      "dimensionality: 173624\n",
      "density: 0.467007\n",
      "\n",
      "\n",
      "================================================================================\n",
      "Elastic-Net penalty\n",
      "________________________________________________________________________________\n",
      "Training: \n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/sli/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/stochastic_gradient.py:117: DeprecationWarning: n_iter parameter is deprecated in 0.19 and will be removed in 0.21. Use max_iter and tol instead.\n",
      "  DeprecationWarning)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.1,\n",
      "       eta0=0.0, fit_intercept=True, l1_ratio=0.15,\n",
      "       learning_rate='optimal', loss='hinge', max_iter=None, n_iter=50,\n",
      "       n_jobs=1, penalty='elasticnet', power_t=0.5, random_state=None,\n",
      "       shuffle=True, tol=None, verbose=0, warm_start=False)\n",
      "train time: 59.976s\n",
      "test time:  0.037s\n",
      "accuracy:   0.689\n",
      "dimensionality: 173624\n",
      "density: 0.006541\n",
      "\n",
      "\n",
      "================================================================================\n",
      "NearestCentroid (aka Rocchio classifier)\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "NearestCentroid(metric='euclidean', shrink_threshold=None)\n",
      "train time: 0.652s\n",
      "test time:  0.060s\n",
      "accuracy:   0.602\n",
      "\n",
      "================================================================================\n",
      "Naive Bayes\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "MultinomialNB(alpha=0.01, class_prior=None, fit_prior=True)\n",
      "train time: 0.911s\n",
      "test time:  0.038s\n",
      "accuracy:   0.608\n",
      "dimensionality: 173624\n",
      "density: 1.000000\n",
      "\n",
      "\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "BernoulliNB(alpha=0.01, binarize=0.0, class_prior=None, fit_prior=True)\n",
      "train time: 0.964s\n",
      "test time:  0.094s\n",
      "accuracy:   0.626\n",
      "dimensionality: 173624\n",
      "density: 1.000000\n",
      "\n",
      "\n",
      "================================================================================\n",
      "LinearSVC with L1-based feature selection\n",
      "________________________________________________________________________________\n",
      "Training: \n",
      "Pipeline(memory=None,\n",
      "     steps=[('feature_selection', SelectFromModel(estimator=LinearSVC(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
      "     intercept_scaling=1, loss='squared_hinge', max_iter=1000,\n",
      "     multi_class='ovr', penalty='l1', random_state=None, tol=0.001,\n",
      "     verbose=0),\n",
      "        norm_order=1, prefit=...ax_iter=1000,\n",
      "     multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,\n",
      "     verbose=0))])\n",
      "train time: 96.057s\n",
      "test time:  0.085s\n",
      "accuracy:   0.681\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nkpST/wHwVNu2i8dQ0QAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1130d7160>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def benchmark(clf):\n",
    "    print('_' * 80)\n",
    "    print(\"Training: \")\n",
    "    print(clf)\n",
    "    t0 = time()\n",
    "    clf.fit(X_train_1, y_train)\n",
    "    train_time = time() - t0\n",
    "    print(\"train time: %0.3fs\" % train_time)\n",
    "\n",
    "    t0 = time()\n",
    "    pred = clf.predict(X_test_1)\n",
    "    test_time = time() - t0\n",
    "    print(\"test time:  %0.3fs\" % test_time)\n",
    "\n",
    "    score = metrics.accuracy_score(y_test, pred)\n",
    "    print(\"accuracy:   %0.3f\" % score)\n",
    "\n",
    "    if hasattr(clf, 'coef_'):\n",
    "        print(\"dimensionality: %d\" % clf.coef_.shape[1])\n",
    "        print(\"density: %f\" % density(clf.coef_))\n",
    "\n",
    "        if opts.print_top10 and feature_names is not None:\n",
    "            print(\"top 10 keywords per class:\")\n",
    "            for i, label in enumerate(target_names):\n",
    "                top10 = np.argsort(clf.coef_[i])[-10:]\n",
    "                print(trim(\"%s: %s\" % (label, \" \".join(feature_names[top10]))))\n",
    "        print()\n",
    "\n",
    "    if opts.print_report:\n",
    "        print(\"classification report:\")\n",
    "        print(metrics.classification_report(y_test, pred,\n",
    "                                            target_names=target_names))\n",
    "\n",
    "    if opts.print_cm:\n",
    "        print(\"confusion matrix:\")\n",
    "        print(metrics.confusion_matrix(y_test, pred))\n",
    "\n",
    "    print()\n",
    "    clf_descr = str(clf).split('(')[0]\n",
    "    return clf_descr, score, train_time, test_time\n",
    "\n",
    "results = []\n",
    "for clf, name in (\n",
    "        (RidgeClassifier(tol=1e-2, solver=\"lsqr\"), \"Ridge Classifier\"),\n",
    "        (Perceptron(n_iter=50), \"Perceptron\"),\n",
    "        (PassiveAggressiveClassifier(n_iter=50), \"Passive-Aggressive\")):\n",
    "    print('=' * 80)\n",
    "    print(name)\n",
    "    results.append(benchmark(clf))\n",
    "    \n",
    "# Train SGD with Elastic Net penalty\n",
    "print('=' * 80)\n",
    "print(\"Elastic-Net penalty\")\n",
    "results.append(benchmark(SGDClassifier(alpha=.0001, n_iter=50,\n",
    "                                       penalty=\"elasticnet\")))\n",
    "\n",
    "# Train NearestCentroid without threshold\n",
    "print('=' * 80)\n",
    "print(\"NearestCentroid (aka Rocchio classifier)\")\n",
    "results.append(benchmark(NearestCentroid()))\n",
    "\n",
    "# Train sparse Naive Bayes classifiers\n",
    "print('=' * 80)\n",
    "print(\"Naive Bayes\")\n",
    "results.append(benchmark(MultinomialNB(alpha=.01)))\n",
    "results.append(benchmark(BernoulliNB(alpha=.01)))\n",
    "\n",
    "print('=' * 80)\n",
    "print(\"LinearSVC with L1-based feature selection\")\n",
    "# The smaller C, the stronger the regularization.\n",
    "# The more regularization, the more sparsity.\n",
    "results.append(benchmark(Pipeline([\n",
    "  ('feature_selection', SelectFromModel(LinearSVC(penalty=\"l1\", dual=False,\n",
    "                                                  tol=1e-3))),\n",
    "  ('classification', LinearSVC(penalty=\"l2\"))])))\n",
    "\n",
    "# make some plots\n",
    "\n",
    "indices = np.arange(len(results))\n",
    "\n",
    "results = [[x[i] for x in results] for i in range(4)]\n",
    "\n",
    "clf_names, score, training_time, test_time = results\n",
    "training_time = np.array(training_time) / np.max(training_time)\n",
    "test_time = np.array(test_time) / np.max(test_time)\n",
    "\n",
    "plt.figure(figsize=(12, 8))\n",
    "plt.title(\"Score\")\n",
    "plt.barh(indices, score, .2, label=\"score\", color='navy')\n",
    "plt.barh(indices + .3, training_time, .2, label=\"training time\",\n",
    "         color='c')\n",
    "plt.barh(indices + .6, test_time, .2, label=\"test time\", color='darkorange')\n",
    "plt.yticks(())\n",
    "plt.legend(loc='best')\n",
    "plt.subplots_adjust(left=.25)\n",
    "plt.subplots_adjust(top=.95)\n",
    "plt.subplots_adjust(bottom=.05)\n",
    "\n",
    "for i, c in zip(indices, clf_names):\n",
    "    plt.text(-.3, i, c)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/sli/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/ridge.py:319: UserWarning: In Ridge, only 'sag' solver can currently fit the intercept when X is sparse. Solver has been automatically changed into 'sag'.\n",
      "  warnings.warn(\"In Ridge, only 'sag' solver can currently fit the \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.691239827668741\n"
     ]
    }
   ],
   "source": [
    "model = RidgeClassifier(tol=1e-2, solver=\"lsqr\")\n",
    "model.fit(X_train_1, y_train)\n",
    "predicted = model.predict(X_test_1)\n",
    "print(np.mean(predicted == y_test))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             precision    recall  f1-score   support\n",
      "\n",
      "         c#       0.80      0.82      0.81      4486\n",
      "     python       0.54      0.46      0.50      2719\n",
      " javascript       0.62      0.72      0.67      7048\n",
      "    android       0.79      0.69      0.74      2937\n",
      "        php       0.88      0.83      0.85      2921\n",
      "       java       0.75      0.73      0.74      5851\n",
      "        c++       0.54      0.48      0.51      5193\n",
      "     jquery       0.56      0.58      0.57      4465\n",
      "    asp.net       0.72      0.81      0.76      5628\n",
      "     iphone       0.89      0.75      0.81      2621\n",
      "\n",
      "avg / total       0.69      0.69      0.69     43869\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from sklearn.metrics import classification_report\n",
    "\n",
    "print(classification_report(y_test, predicted, target_names=target_names))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
